<?php

namespace app\admin\model\scanwork;

use think\Model;

/**
 * 工资核算模型
 */
class WageCalculation extends Model
{
    // 表名
    protected $name = 'scanwork_wage_calculation';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';
    
    // 追加属性
    protected $append = [
        'status_text'
    ];
    
    // 工资核算状态
    public function getStatusList()
    {
        return [
            '0' => __('待确认'),
            '1' => __('已确认'),
            '2' => __('已发放')
        ];
    }

    public function getStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['status']) ? $data['status'] : '');
        $list = $this->getStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }

    // 关联员工
    public function employee()
    {
        return $this->belongsTo('app\admin\model\scanwork\Employee', 'employee_id', 'id');
    }

    // 关联系统用户
    public function user()
    {
        return $this->belongsTo('app\common\model\User', 'employee_id', 'id');
    }

    // 关联确认人
    public function confirmUser()
    {
        return $this->belongsTo('app\common\model\User', 'confirm_user_id', 'id');
    }

    // 获取核算编码
    public function getCalculationCodeAttr($value, $data)
    {
        if (empty($value) && isset($data['id'])) {
            $value = 'GZ-' . date('Y') . '-' . str_pad($data['id'], 3, '0', STR_PAD_LEFT);
        }
        return $value;
    }

    // 检查核算编码是否唯一
    public function checkCodeUnique($code, $id = null)
    {
        $where = ['calculation_code' => $code];
        if ($id) {
            $where['id'] = ['<>', $id];
        }
        return $this->where($where)->count() == 0;
    }

    // 获取核算明细
    public function getCalculationDetailsAttr($value, $data)
    {
        if (is_string($value)) {
            return json_decode($value, true) ?: [];
        }
        return $value ?: [];
    }

    // 设置核算明细
    public function setCalculationDetailsAttr($value, $data)
    {
        if (is_array($value)) {
            return json_encode($value, JSON_UNESCAPED_UNICODE);
        }
        return $value;
    }

    // 自动计算工资
    public function calculateWage($employeeId, $calculationDate, $workType = 'piece')
    {
        $employee = \app\admin\model\scanwork\Employee::get($employeeId);
        if (!$employee) {
            throw new \Exception('员工不存在');
        }

        $startTime = strtotime($calculationDate . ' 00:00:00');
        $endTime = strtotime($calculationDate . ' 23:59:59');

        $calculationDetails = [];
        $totalQuantity = 0;
        $totalHours = 0;
        $pieceWage = 0;
        $timeWage = 0;
        $overtimeWage = 0;

        if ($workType == 'piece') {
            // 计件工资计算
            $reports = \app\admin\model\scanwork\Report::with(['allocation.process', 'allocation.model'])
                ->where('user_id', $employee->user_id)
                ->where('status', 1)
                ->where('quality_status', 1)
                ->where('createtime', '>=', $startTime)
                ->where('createtime', '<=', $endTime)
                ->select();

            foreach ($reports as $report) {
                $allocation = $report->allocation;
                $process = $allocation->process;
                $model = $allocation->model;

                // 获取工序工价
                $processPrice = \app\admin\model\scanwork\ProcessPrice::where([
                    'process_id' => $process->id,
                    'model_id' => $model->id
                ])->find();

                if ($processPrice) {
                    $price = $processPrice->price;
                    $wage = $report->quantity * $price;
                    $pieceWage += $wage;
                    $totalQuantity += $report->quantity;

                    $calculationDetails[] = [
                        'type' => 'piece',
                        'allocation_id' => $allocation->id,
                        'process_name' => $process->name,
                        'model_name' => $model->name,
                        'quantity' => $report->quantity,
                        'price' => $price,
                        'wage' => $wage,
                        'report_time' => date('H:i:s', $report->createtime)
                    ];
                }
            }
        } else {
            // 计时工资计算
            $allocations = \app\admin\model\scanwork\Allocation::with(['process', 'model'])
                ->where('user_id', $employee->user_id)
                ->where('work_type', 'time')
                ->where('createtime', '>=', $startTime)
                ->where('createtime', '<=', $endTime)
                ->select();

            foreach ($allocations as $allocation) {
                $process = $allocation->process;
                $model = $allocation->model;

                // 获取工序工价
                $processPrice = \app\admin\model\scanwork\ProcessPrice::where([
                    'process_id' => $process->id,
                    'model_id' => $model->id
                ])->find();

                if ($processPrice && $allocation->actual_hours > 0) {
                    $hourlyRate = $processPrice->time_price;
                    $hours = $allocation->actual_hours;
                    $wage = $hours * $hourlyRate;
                    $timeWage += $wage;
                    $totalHours += $hours;

                    // 计算加班工资
                    $overtimeHours = max(0, $hours - 8); // 超过8小时算加班
                    if ($overtimeHours > 0) {
                        $overtimeRate = $hourlyRate * $employee->overtime_rate;
                        $overtimeWage += $overtimeHours * $overtimeRate;
                    }

                    $calculationDetails[] = [
                        'type' => 'time',
                        'allocation_id' => $allocation->id,
                        'process_name' => $process->name,
                        'model_name' => $model->name,
                        'hours' => $hours,
                        'hourly_rate' => $hourlyRate,
                        'wage' => $wage,
                        'overtime_hours' => $overtimeHours,
                        'overtime_wage' => $overtimeHours * $hourlyRate * $employee->overtime_rate
                    ];
                }
            }
        }

        $totalWage = $pieceWage + $timeWage + $overtimeWage;

        return [
            'total_quantity' => $totalQuantity,
            'total_hours' => $totalHours,
            'piece_wage' => $pieceWage,
            'time_wage' => $timeWage,
            'overtime_wage' => $overtimeWage,
            'total_wage' => $totalWage,
            'calculation_details' => $calculationDetails
        ];
    }

    // 创建工资核算记录
    public function createCalculation($employeeId, $calculationDate, $workType = 'piece')
    {
        $employee = \app\admin\model\scanwork\Employee::get($employeeId);
        if (!$employee) {
            throw new \Exception('员工不存在');
        }

        // 检查是否已存在该日期的核算记录
        $existing = $this->where([
            'employee_id' => $employeeId,
            'calculation_date' => $calculationDate,
            'work_type' => $workType
        ])->find();

        if ($existing) {
            throw new \Exception('该日期的工资核算记录已存在');
        }

        // 计算工资
        $calculationData = $this->calculateWage($employeeId, $calculationDate, $workType);

        // 创建核算记录
        $data = [
            'calculation_code' => $this->generateCalculationCode(),
            'employee_id' => $employeeId,
            'calculation_date' => $calculationDate,
            'work_type' => $workType,
            'total_quantity' => $calculationData['total_quantity'],
            'total_hours' => $calculationData['total_hours'],
            'piece_wage' => $calculationData['piece_wage'],
            'time_wage' => $calculationData['time_wage'],
            'overtime_wage' => $calculationData['overtime_wage'],
            'total_wage' => $calculationData['total_wage'],
            'calculation_details' => $calculationData['calculation_details'],
            'status' => 0,
            'createtime' => time()
        ];

        return $this->create($data);
    }

    // 生成核算编码
    private function generateCalculationCode()
    {
        $prefix = 'GZ-' . date('Y') . '-';
        $lastCode = $this->where('calculation_code', 'like', $prefix . '%')
            ->order('calculation_code desc')
            ->value('calculation_code');
        
        if ($lastCode) {
            $lastNumber = intval(substr($lastCode, -3));
            $newNumber = $lastNumber + 1;
        } else {
            $newNumber = 1;
        }
        
        return $prefix . str_pad($newNumber, 3, '0', STR_PAD_LEFT);
    }

    // 确认工资核算
    public function confirm($confirmUserId = null)
    {
        if ($this->status != 0) {
            throw new \Exception('只有待确认状态的工资核算才能确认');
        }

        $this->save([
            'status' => 1,
            'confirm_time' => time(),
            'confirm_user_id' => $confirmUserId
        ]);
    }

    // 发放工资
    public function pay()
    {
        if ($this->status != 1) {
            throw new \Exception('只有已确认状态的工资核算才能发放');
        }

        $this->save(['status' => 2]);
    }

    // 获取员工工资统计
    public function getEmployeeWageStats($employeeId, $startDate = null, $endDate = null)
    {
        $where = ['employee_id' => $employeeId];
        
        if ($startDate) {
            $where['calculation_date'] = ['>=', $startDate];
        }
        if ($endDate) {
            $where['calculation_date'] = ['<=', $endDate];
        }

        $calculations = $this->where($where)->select();

        $totalWage = $calculations->sum('total_wage');
        $totalPieceWage = $calculations->sum('piece_wage');
        $totalTimeWage = $calculations->sum('time_wage');
        $totalOvertimeWage = $calculations->sum('overtime_wage');
        $totalQuantity = $calculations->sum('total_quantity');
        $totalHours = $calculations->sum('total_hours');

        return [
            'total_wage' => $totalWage,
            'total_piece_wage' => $totalPieceWage,
            'total_time_wage' => $totalTimeWage,
            'total_overtime_wage' => $totalOvertimeWage,
            'total_quantity' => $totalQuantity,
            'total_hours' => $totalHours,
            'calculation_count' => count($calculations),
            'confirmed_count' => $calculations->where('status', '>=', 1)->count(),
            'paid_count' => $calculations->where('status', 2)->count()
        ];
    }

    // 批量创建工资核算
    public function batchCreateCalculations($employeeIds, $calculationDate, $workType = 'piece')
    {
        $results = [];
        $successCount = 0;
        $errorCount = 0;
        $errors = [];

        foreach ($employeeIds as $employeeId) {
            try {
                $calculation = $this->createCalculation($employeeId, $calculationDate, $workType);
                $results[] = $calculation;
                $successCount++;
            } catch (\Exception $e) {
                $errorCount++;
                $errors[] = "员工ID {$employeeId}: " . $e->getMessage();
            }
        }

        return [
            'success_count' => $successCount,
            'error_count' => $errorCount,
            'errors' => $errors,
            'results' => $results
        ];
    }

    // 获取工资核算汇总
    public function getWageSummary($startDate = null, $endDate = null)
    {
        $where = [];
        
        if ($startDate) {
            $where['calculation_date'] = ['>=', $startDate];
        }
        if ($endDate) {
            $where['calculation_date'] = ['<=', $endDate];
        }

        $calculations = $this->with(['employee'])->where($where)->select();

        $summary = [
            'total_employees' => $calculations->group('employee_id')->count(),
            'total_calculations' => count($calculations),
            'total_wage' => $calculations->sum('total_wage'),
            'total_piece_wage' => $calculations->sum('piece_wage'),
            'total_time_wage' => $calculations->sum('time_wage'),
            'total_overtime_wage' => $calculations->sum('overtime_wage'),
            'total_quantity' => $calculations->sum('total_quantity'),
            'total_hours' => $calculations->sum('total_hours'),
            'pending_count' => $calculations->where('status', 0)->count(),
            'confirmed_count' => $calculations->where('status', 1)->count(),
            'paid_count' => $calculations->where('status', 2)->count()
        ];

        return $summary;
    }
}
